﻿'use strict';

var OnlineOS = (function ($, j, undefined) { 

	// global object
	var oos = { };

	// config object
	var config = oos.config = { };

	// url used to communicate with server
	var pageUrl = config.pageUrl = 'oos.html';

	// object containing all constructor's functions
	var ctor = oos.ctor = { };

	// object containins all statics functions
	var sfn = oos.sfn = { };

	// object containing all shared functions
	var fn = oos.fn = { };

	var defaultErrorFunc = sfn.defaultErrorFunc = function() {
		alert('Error!');
	};
	var serverRequestId = 0;
	// send a server request
	var serverRequest = sfn.serverRequest = function(data, success, error) {
		if(!error)
			error = defaultErrorFunc;
		data.format = 'json';
		data.requestId = serverRequestId;
		serverRequestId++;
		j.sfn.submitAjaxData(data, pageUrl, 'post', success, error);
	};

	// send a server command
	var serverCommand = sfn.serverCommand = function(command, data, success, error) {
		data.command = command;
		serverRequest(data, success, error);
	};
	
	// resize browser window event
	var windowResize = sfn.windowResize = function() {
		var $window = $(window);
		var me = oos.screen;
		if(me) {
			me.$.hide();
			me.resolution = {
				width: $window.width(),
				height: $window.height()
			};
			j.console.info('>: Resolution is ' + me.resolution.width +'x' + me.resolution.height + '.');
			me.$.show();
			me.$.width(me.resolution.width).height(me.resolution.height);
			me.containerResized();
		}
	};

	// startbutton click event
	var startButtonClick = sfn.startButtonClick =  function() {
		var me = oos.screen;
		if(me) {
			me.startMenu.$.toggle();
			me.taskBar.startButton.$.toggleClass('down');
			me.taskBar.startButton.text.$.toggleClass('focus');
			me.setFocus(me.taskBar.startButton);
		}
	};

	// cancel the default browser right click context menu
	var windowContextMenu = sfn.windowContextMenu = function(e) { return false; };

	// return the src of an item's icon
	var getItemIcon = sfn.getItemIcon = function(obj) {
		if(obj.iconSrc)
			return obj.iconSrc;
		if(obj.type === 'directory')
			return '/Images/Icons/OOS/Folder.png';
		return '/Images/html5-icon.png';
	};

	// set event to changes src on images when mouse enter and leave images (one condition is that img have to have src set to the other value)
	var setMouseEnterLeaveImages = sfn.setMouseEnterLeaveImages = function($obj, imgSrcEnter, imgSrcLeave) {
		$obj.mouseenter(function() {
			if($obj.attr('src') === imgSrcLeave) {
				$obj.attr('src', imgSrcEnter);
			}
		});
		$obj.mouseleave(function() {
			if($obj.attr('src') === imgSrcEnter) {
				$obj.attr('src', imgSrcLeave);
			}
		});
	};

	// fill the parent (width and height) with the current control
	var fillParent = fn.fillParent = function() {
		var toWidth = this.$.outerWidth(true);
		var toHeight = this.$.outerHeight(true);
		var tWidth = this.$.width();
		var tHeight = this.$.height();
		// hide and then resize (when minimizing to avoid scrollbars to stay when they should not)
		this.$.hide();
		var height = this.parent.$.innerHeight();
		var width = this.parent.$.innerWidth();
		// difference between assigned height/width and the outer height/width
		var difW = toWidth - tWidth;
		var difH = toHeight - tHeight;
		// assign new size
		this.$.height(height - difH);
		this.$.width(width - difW);
		// finally show the element
		this.$.show();
	};

	// call all the children's containerResized function
	var resized = fn.resized = function() {
		if(this.children) {
			var i=0;
			for(;i<this.children.length;i++) {
				if(this.children[i].containerResized)
					this.children[i].containerResized();
			}
		}
	};

	// set focus of the current object
	var setFocus = fn.setFocus = function(focusable) {
		var different = (focusable !== this.focus);
		if(different)
			oos.screen.contextMenu.$.hide();
		if(this.focus && different)
			this.focus.unfocus();
		this.focus = focusable;
		if(focusable && different)
			focusable.focus();
	};

	// display a unique context menu at mouse position
	var showContextMenu = fn.showContextMenu = function(e, items) {
		var me = oos.screen.contextMenu;
		me.list.$.html('');
		var i=0;
		for(;i<items.length;i++)
			me.list.addItem(items[i].text, items[i].className, items[i].disabled);
		me.$.show().offset({left: e.pageX, top: e.pageY});
	};

	var addItem = fn.addItem = function(caption, className, disabled) {
		var li = new ctor.Object({tagName: 'li', className: className, disabled: disabled, caption: caption});
		if(this.$[0].tagName === 'OL' || this.$[0].tagName === 'UL') {
			this.$.append(li.$);
		} else {
			if(!this.menuStrip) {
				this.menuStrip = new ctor.Object({tagName: 'ol', className: 'menuStrip'});
				this.$.append(this.menuStrip.$);
			}
			this.menuStrip.$.append(li.$);
		}
		return li;
	};

	// create an object
	ctor.Object = function(params) {
		var me = { };
		if(!params)
			params = { };
		if(params.tagName && !params.html) {
			if(params.emptyNode)
				params.html = '<' + params.tagName + ' />';
			else
				params.html = '<' + params.tagName + '></' + params.tagName + '>';
		}
		if(params.html)
			me.$ = $(params.html);
		if(params.containerResized)
			me.containerResized = params.containerResized;
		else
			me.containerResized = resized;
		if(me.$) {
			if(params.className)
				me.$.addClass(params.className);
			if(params.src)
				me.$.attr('src', params.src);
			if(params.alt)
				me.$.attr('alt', params.alt);
			if(params.title)
				me.$.attr('title', params.title);
			if(params.disabled)
				me.$.addClass('disabled');
			if(params.caption)
				me.$.text(params.caption);
		}
		if(params.parent)
			me.parent = params.parent;
		return me;
	};

	// oos objects
	ctor.Screen = function() {
		var me = new ctor.Object({tagName: 'div', className: 'screen'});
		var desktop = me.desktop = new ctor.Desktop(me);
		var startMenu = me.startMenu = new ctor.StartMenu(me);
		var taskBar = me.taskBar = new ctor.TaskBar(me);
		var contextMenu = me.contextMenu = new ctor.ContextMenu(me);

		// assign size dependant children
		me.children = [desktop, taskBar];

		// add inner objects
		desktop.$.appendTo(me.$);
		startMenu.$.appendTo(me.$);
		taskBar.$.appendTo(me.$);
		contextMenu.$.appendTo(me.$);

		// insert to html document
		var $body = $('body');
		me.$.appendTo($body);

		// functions
		me.setFocus = setFocus;
		me.showContextMenu = showContextMenu;

		return me;
	};
	ctor.TaskBar = function(screen) {
		var me = new ctor.Object({parent: screen, tagName: 'div', className: 'taskBar'});
		var startButton = me.startButton = new ctor.StartButton(me);
		var programBar = me.programBar = new ctor.Object({tagName: 'div', className: 'programBar'});
		
		startButton.$.appendTo(me.$);
		programBar.$.appendTo(me.$);

		me.$.click(function(e) {
			if(e.target === me.$[0] || e.target === programBar.$[0])
				screen.setFocus(null);
		});

		me.containerResized = function() {
			var width = me.$.width();
			width -= startButton.$.outerWidth(true);
			//width -= $tray.outerWidth(true);
			programBar.$.width(width);
		};
		return me;
	};
	ctor.Desktop = function(screen) {
		var i;
		var me = new ctor.Object({tagName: 'div', className: 'desktop', parennt: screen});
		var icons = new ctor.Object({tagName: 'ol', className: 'icons'});

		icons.$.appendTo(me.$);

		var startDragX;
		var startDragY;
		var iconStart;
		var $draggedIcon;
		var startDragIcon = function(e) {
			if(e.button !== 0)
				return
			var $this = $(this);
			$draggedIcon = $this;
			iconStart = {
				left: $this.offset().left,
				top: $this.offset().top
			};
			startDragX = e.pageX;
			startDragY = e.pageY;
			$(window).mousemove(moveDragIcon).mouseup(endDragIcon);
		};
		var moveDragIcon = function(e) {
			var dx = e.pageX - startDragX;
			var dy = e.pageY - startDragY;
			$draggedIcon.offset({left: iconStart.left + dx, top: iconStart.top + dy});
		};
		var endDragIcon = function(e) {
			var $this = $draggedIcon;
			var iw = $this.width();
			var ih = $this.height();
			var ix = parseInt($this.offset().left / iw);
			var iy = parseInt($this.offset().top / ih);
			$this.offset({left: ix * iw, top: iy * ih});
			$(window).unbind('mousemove',moveDragIcon).unbind('mouseup',endDragIcon);
		};

		var windows = [];
		me.parent = screen;
		me.addIcon = function(iconSrc, obj) {
			var li = new ctor.Object({tagName: 'li', className: 'icon'});
			li.$.appendTo(icons.$);
			var icon = new ctor.Object({tagName: 'img', emptyTag: true, className:'icon', src: iconSrc, title: obj.name});
			var text = new ctor.Object({tagName: 'div', className: 'text'});
			var span = new ctor.Object({tagName: 'span', className: 'text'});
			span.$.text(obj.name);
			li.$.mousedown(startDragIcon);
			span.$.appendTo(text.$);
			icon.$.appendTo(li.$);
			text.$.appendTo(li.$);

			li.$.data('path', obj.path);
			li.$.data('directory', obj.type === 'directory');

			li.focus = function() {
				li.$.addClass('focus');
			};
			li.unfocus = function() {
				li.$.removeClass('focus');
			};
			li.$.mousedown(function(e) {
				screen.setFocus(li);
				if(e.button === 2 && li.showContextMenu)
					li.showContextMenu(e);
				else
					screen.contextMenu.$.hide();
			});
			li.showContextMenu = function(e) {
				screen.showContextMenu(e, [
					{text: 'Ouvrir', className: null},
					{text: 'Modifier', className: 'separationBottom'},
					{text: 'Couper', className: 'separationTop'},
					{text: 'Copier', className: null},
					{text: 'Coller', className: 'separationBottom', disabled: true},
					{text: 'Supprimer', className: 'separationTop'},
					{text: 'Renommer', className: 'separationBottom'},
					{text: 'Propriétés', className: 'separationTop'},
				]);
			};

			return li;
		};
		me.addWindow = function(iconSrc, title, width, height) {
			var w = new ctor.Window(me, iconSrc, title, width, height);
			w.$.css('z-index', windows.length).addClass('focus');
			windows.push(w);
			w.$.appendTo(me.$);
			me.setFocus(w);
			return w;
		};
		me.removeWindow = function(window) {
			var index = -1;
			var z = parseInt(window.$.css('z-index'));
			for(i=0;i<windows.length;i++) {
				if(windows[i] === window) {
					windows.splice(i, 1);
					i--;
				} else {
					var other = parseInt(windows[i].$.css('z-index'));
					if(other > z) {
						windows[i].$.css('z-index', other - 1)
					}
				}
			}
		};
		me.containerResized = function() {
			for(i=0;i<windows.length;i++) {
				windows[i].containerResized();
			}
		};
		me.$.mousedown(function(e) {
			if(e.target === me.$[0] || e.target == icons.$[0])
				screen.setFocus(null);
		});
		me.setFocus = function(window) {
			if(window) {
				var z = parseInt(window.$.css('z-index'));
				for(i=0;i<windows.length;i++) {
					if(windows[i] !== window) {
						var other = parseInt(windows[i].$.css('z-index'));
						if(other > z) {
							windows[i].$.css('z-index', other - 1)
						}
					}
				}
				window.$.css('z-index', windows.length - 1);
			}
			screen.setFocus(window);
		};

		return me;
	};
	ctor.StartMenu = function(screen) {
		var params = {
			parent: screen,
			tagName: 'div',
			className: 'startMenu'
		};
		var me = new ctor.Object(params);
		var top = new ctor.Object({tagName: 'div', className: 'top'});
		var left = new ctor.Object({tagName: 'div', className: 'left'});
		var right = new ctor.Object({tagName: 'div', className: 'right'});
		var bottom = new ctor.Object({tagName: 'div', className: 'bottom'});
		var iconDiv = new ctor.Object({tagName: 'div', className: 'top'});
		var icon = new ctor.Object({tagName: 'img', emptyTag: true, className: 'icon', src: '/Images/html5-icon.png'});
		var leftList = new ctor.Object({tagName: 'ol', className: 'menuStrip'});
		var rightList = new ctor.Object({tagName: 'ol', className: 'menuStrip'});

		top.$.appendTo(me.$);
		bottom.$.appendTo(me.$);

		left.$.appendTo(top.$);
		right.$.appendTo(top.$);
		iconDiv.$.appendTo(right.$);
		icon.$.appendTo(iconDiv.$);
		
		leftList.$.appendTo(left.$);
		rightList.$.appendTo(right.$);

		me.addRightItem = function(caption, className) {
			var li = new ctor.Object({tagName: 'li', className: className});
			rightList.$.append(li.$);
			li.$.text(caption);
			return li;
		};
		me.addLeftItem = function(caption, className, iconSrc) {
			var li = new ctor.Object({tagName: 'li', className: className});
			leftList.$.append(li.$);
			var icon = new ctor.Object({tagName:'img', emptyTag: true, className:'icon', src:iconSrc});
			li.$.text(caption);
			li.$.prepend(icon.$);
			return li;
		};
		me.parent = screen;
		return me;
	};
	ctor.Button = function(params) {
		var me = new ctor.Object(params);
		me.$.addClass('button');
		if(params.text)
			me.$.text(params.text);
		return me;
	};
	ctor.StartButton = function(taskBar) {
		var me = new ctor.Button({tagName: 'div', className: 'startButton', parent: taskBar});
		var icon = new ctor.Object({tagName: 'img', emptyTag: true, className: 'icon', src: '/Images/html5-icon.png'});
		var text = new ctor.Object({tagName: 'div', className: 'text'});
		me.icon = icon;
		me.text = text;
		text.$.text('Démarrer');
		icon.$.appendTo(me.$);
		text.$.appendTo(me.$);
		me.unfocus = function() {
			taskBar.parent.startMenu.$.hide();
			me.$.removeClass('down');
			me.text.$.removeClass('focus');
		};
		me.focus = function() {
		};
		me.$.click(oos.sfn.startButtonClick)
		return me;
	};
	ctor.Panel = function(parent, className) {
		var me = new ctor.Object({tagName: 'div', className: className});
		var i;
		me.parent = parent;
		me.children = [];
		me.containerResized = function() {
			for(i=0;i<me.children.length;i++) {
				me.children[i].containerResized();
			}
		};
		return me;
	};
	ctor.ListView = function(parent, className) {
		var me = new ctor.Object({tagName: 'div', className: 'listView'});
		var icons = new ctor.Object({tagName: 'ol', className: 'icons'});
		icons.$.appendTo(me.$);
		if(className)
			me.$.addClass(className);
		me.parent = parent;
		me.addIcon = function(iconSrc, obj) {
			var li = new ctor.Object({tagName: 'li', className:'icon'});
			icons.$.append(li.$);
			var icon = new ctor.Object({tagName: 'img', emptyTag: true, className: 'icon', src: iconSrc, title: obj.name});
			var text = new ctor.Object({tagName: 'div', className: 'text'});
			var span = new ctor.Object({tagName: 'span', className: 'text'});
			span.$.text(obj.name);
			//li.$.mousedown(startDragIcon);
			span.$.appendTo(text.$);
			icon.$.appendTo(li.$);
			text.$.appendTo(li.$);

			li.focus = function() {
				li.$.addClass('focus');
			};
			li.unfocus = function() {
				li.$.removeClass('focus');
			};
			li.$.mousedown(function(e) {
				if(parent.setFocus)
					parent.setFocus(li);
			});

			return li;
		};

		var resetItemPosition = function() {
			var $lis = $('li', icons.$);

			var size = null;
			var baseOffst = {left: me.$.offset().left, top: me.$.offset().top};
			var pos = {left:0, top:0};
			var width = me.$.width();
			var height = me.$.height();
			var isVerticalList = false;
			var isScrollable = true;
			var maxWidth = -1;
			var i = 0;

			for(;i<$lis.length;i++) {
				var $li = $($lis[i]);
				size = { width: $li.width(), height: $li.height() };
				if(size.width > maxWidth)
					maxWidth = size.width;
					
				if(isVerticalList) {
					$li.offset({left: baseOffst.left + pos.left, top: baseOffst.top + pos.top});

					pos.top += size.height;
					if(pos.top + size.height + 16 > height) {
						pos.top = 0;
						pos.left += size.width;
					}
				} else {
					$li.offset({left: baseOffst.left + pos.left, top: baseOffst.top + pos.top});

					pos.left += size.width;
					if(pos.left + size.width + 16 > width) {
						pos.left = 0;
						pos.top += size.height;
					}
				}
			}


		};

		me.containerResized = function() {
			resetItemPosition();
		};

		me.refreshList = function(path, extension) {
			icons.$.html('');
			oos.retrieveDirectory(path, extension, false, function(data) {
				var size = null;
				var baseOffst = {left: me.$.offset().left, top: me.$.offset().top};
				var pos = {left:0, top:0};
				var width = me.$.width();
				var height = me.$.height();
				var isVerticalList = false;
				var isScrollable = true;
				var maxWidth = -1;
				if(data.directory) {
					var i = 0;
					for(;i<data.directory.length;i++) {
						var srcIcon = getItemIcon(data.directory[i]);
						var icon = me.addIcon(srcIcon,data.directory[i]);
						icon.$.data('path', (data.path + '\\' + data.directory[i].name).replace('\\\\','\\'));
						icon.$.data('name', data.directory[i].name);
						if(data.directory[i].type === 'directory')
							icon.$.data('directory', true);
						size = { width: icon.$.width(), height: icon.$.height() };
						if(size.width > maxWidth)
							maxWidth = size.width;
					
						if(isVerticalList) {
							icon.$.offset({left: baseOffst.left + pos.left, top: baseOffst.top + pos.top});

							pos.top += size.height;
							if(pos.top + size.height + 16 > height) {
								pos.top = 0;
								pos.left += size.width;
							}
						} else {
							icon.$.offset({left: baseOffst.left + pos.left, top: baseOffst.top + pos.top});

							pos.left += size.width;
							if(pos.left + size.width + 16 > width) {
								pos.left = 0;
								pos.top += size.height;
							}
						}
					}
				}

			}, function() { alert('error'); });
		}


		return me;
	};
	ctor.TableView = function(parent, className) {
		var me = new ctor.Object({tagName: 'div', className:'listView'});
		var header = new ctor.Object({tagName: 'div', className:'header'});
		var icons = new ctor.Object({tagName: 'table', className:'icons'});
		var headHtml = '<thead><tr><th class="name">Nom</th><th class="modified">Modifié le</th><th class="type">Type</th><th class="size">Taille</th><th class="filler"></th></tr></thead>';
		var $header = $(headHtml);
		var $fakeHeader = $('<table class="icons">' + headHtml + '</table>');
		$fakeHeader.appendTo(header.$);
		$header.appendTo(icons.$);
		header.$.appendTo(me.$);
		icons.$.appendTo(me.$);

		if(className)
			me.$.addClass(className);

		me.parent = parent;
		me.addIcon = function(iconSrc, obj) {
			var tr = new ctor.Object({tagName: 'tr', className:'icon'});
			icons.$.append(tr.$);
			var icon = new ctor.Object({tagName: 'img', emptyTag: true, className:'icon', src: iconSrc, title: obj.name});
			var text = new ctor.Object({tagName: 'div', className:'text'});
			var span = new ctor.Object({tagName: 'span', className:'text'});

			var tdName = new ctor.Object({tagName: 'td', className:'name'});
			var tdModified = new ctor.Object({tagName: 'td', className:'modified'});
			var tdType = new ctor.Object({tagName: 'td', className:'type'});
			var tdSize = new ctor.Object({tagName: 'td', className:'size'});

			tr.$.append(tdName.$);
			tr.$.append(tdModified.$);
			tr.$.append(tdType.$);
			tr.$.append(tdSize.$);

			span.$.text(obj.name);
			//li.$.mousedown(startDragIcon);
			span.$.appendTo(text.$);
			icon.$.appendTo(tdName.$);
			text.$.appendTo(tdName.$);

			tdModified.$.text(obj.modified);
			tdType.$.text(obj.type);
			tdSize.$.text(obj.size);

			tr.focus = function() {
				tr.$.addClass('focus');
			};
			tr.unfocus = function() {
				tr.$.removeClass('focus');
			};
			tr.$.mousedown(function(e) {
				if(parent.setFocus)
					parent.setFocus(tr);
			});

			return tr;
		};

		me.containerResized = function() {
			header.$.width(icons.$.width());
		}
		me.$.scroll(function() {
			header.$.css('top', me.$.scrollTop() + 'px');
		});

		me.refreshList = function(path, extension) {
			$header.remove();
			icons.$.html('');
			$header.appendTo(icons.$);
			me.containerResized();
			oos.retrieveDirectory(path, extension, false, function(data) {
				if(data.directory) {
					var i = 0;
					for(;i<data.directory.length;i++) {
						var srcIcon = getItemIcon(data.directory[i]);
						var icon = me.addIcon(srcIcon,data.directory[i]);
						icon.$.data('path', data.directory[i].path);
						icon.$.data('name', data.directory[i].name);
						if(data.directory[i].type === 'directory')
							icon.$.data('directory', true);
					}
					me.containerResized();
				}

			}, function() { alert('error'); });
		};



		return me;
	};
	ctor.HierarchyView = function(parent, className) {
		var me = new ctor.Object({tagName: 'div', className: 'hierarchyView'});
		var ol = new ctor.Object({tagName: 'ol', className: 'icons'});
		me.$.append(ol.$);
		if(className)
			me.$.addClass(className);

		var focused = null;

		var addItem = function(iconSrc, data) {
			if(!this.ol) {
				this.ol = new ctor.Object({tagName: 'ol', className: 'icons'});
				this.$.append(this.ol.$);
			}
			var li = new ctor.Object({tagName: 'li', className: 'icon'});
			var showHide = new ctor.Object({tagName:'div', className: 'expando'});
			var div = new ctor.Object({tagName: 'div', className: 'content'});
			var icon = new ctor.Object({tagName:'img', emptyTag: true, className: 'icon', src: iconSrc});
			var span = new ctor.Object({tagName:'span', className: 'text'});
			li.$.append(showHide.$);
			li.$.append(div.$);
			div.$.append(icon.$);
			div.$.append(span.$);

			if(data.path)
				li.$.data('path', data.path);
			if(data.type)
				li.$.data('directory', data.type === 'directory');
			if(data.name)
				span.$.text(data.name);
			div.$.click(function() {
				if(focused)
					focused.$.removeClass('focus');
				focused = li;
				li.$.addClass('focus');
			});
			if(data.hasChildren) {
				li.$.addClass('closed');
				showHide.$.click(function() {
					if(li.$.hasClass('closed')) {
						li.$.removeClass('closed');
						li.$.addClass('open');
						if(!li.ol) {
							oos.retrieveDirectory(li.$.data('path'), '*', true, function(data) {
								if(data.directory) {
									var i = 0;
									for(;i<data.directory.length;i++) {
										var srcIcon = getItemIcon(data.directory[i]);
										if(data.directory[i].type === 'directory')
											li.addItem(srcIcon, data.directory[i]);
									}
								}

							}, function() { alert('error'); });
						}
					} else if(li.$.hasClass('open')) {
						li.$.removeClass('open');
						li.$.addClass('closed');
					}
				});
			}
			this.ol.$.append(li.$);
			li.addItem = addItem;
			return li;
		};
		me.ol = ol;
		me.addItem = addItem;

		me.refreshList = function(path) {
			var target = this;
			if(this.ol) {
				var tOl = this.ol;
				this.ol.$.html('');
			}
			oos.retrieveDirectory(path, '*', true, function(data) {
				if(data.directory) {
					var i = 0;
					for(;i<data.directory.length;i++) {
						var srcIcon = getItemIcon(data.directory[i]);
						if(data.directory[i].type === 'directory')
							target.addItem(srcIcon, data.directory[i]);
					}
					me.containerResized();
				}

			}, function() { alert('error'); });
		};

		return me;
	};
	ctor.Window = function(desktop, iconSrc, title, width, height, options) {
		var me = new ctor.Object({tagName: 'div', className: 'window'});
		if(width)
			me.$.width(width);
		if(height)
			me.$.height(height);
		var titleBar = new ctor.Object({tagName: 'div', className: 'titleBar'});
		if(iconSrc)
			var icon = new ctor.Object({tagName: 'img', emptyTag: true, className: 'icon', src: iconSrc});
		var text = new ctor.Object({tagName: 'div', className: 'text'});
		var taskbarButton = new ctor.Button({tagName: 'div'});
		if(iconSrc)
			var taskbarIcon = new ctor.Object({tagName: 'img', className: 'icon', src: iconSrc});
		var menuStrip = null;
		var content = new ctor.Panel(me, 'content');
		me.content = content;
		me.caption = text;
		var baseContentResized = content.containerResized;
		content.containerResized = function() {
			var height = me.$.height();
			height -= titleBar.$.outerHeight(true);
			if(menuStrip)
				height -= menuStrip.$.outerHeight(true);
			content.$.height(height);
			baseContentResized();
		};

		me.addMenuItem = function(caption) {
			if(!menuStrip) {
				menuStrip = new ctor.Object({tagName: 'ol', className: 'menuStrip'});
				titleBar.$.after(menuStrip.$);
				menuStrip.$.click(function() {
					menuStrip.$.toggleClass('down');
				});
				content.containerResized();
			}
			var li = new ctor.Object({tagName: 'li'});
			li.addItem = addItem;
			menuStrip.$.append(li.$);
			li.$.text(caption);
			return li;
		};

		var focused = null;
		me.setFocus = function(focusable) {
			if(focused === focusable)
				return;
			if(focused && focused.unfocus)
				focused.unfocus();
			focused = focusable;
			if(focused && focused.focus)
				focused.focus();
			if(desktop.setFocus)
				desktop.setFocus(me);
		};

		var actions = new ctor.Object({tagName: 'div', className: 'actions'});
		var minimize = new ctor.Button({tagName: 'div', className: 'minimize'});
		var minimizeIcon = new ctor.Object({tagName:'img', emptyTag:true, className:'icon', src:'/Images/Icons/OOS/minimize.png', alt: '_'});
		minimize.$.append(minimizeIcon.$);
		var maximize = new ctor.Button({tagName: 'div', className: 'maximize'});
		var maximizeIcon = new ctor.Object({tagName:'img', emptyTag:true, className:'icon', src:'/Images/Icons/OOS/maximize.png', alt: '+'});
		maximize.$.append(maximizeIcon.$);
		var close = new ctor.Button({tagName: 'div', className: 'close'});
		var closeIcon = new ctor.Object({tagName:'img', emptyTag:true, className:'icon', src:'/Images/Icons/OOS/close.png', alt: 'X'});
		close.$.append(closeIcon.$);

		me.trimHeight = function() {
			var height = titleBar.$.outerHeight(true);
			if(menuStrip)
				height += menuStrip.$.outerHeight(true);
			height += content.$.height();
			me.$.height(height);
			content.containerResized();
		};
		me.centerParent = function() {
			var width = me.$.outerWidth(true);
			var height = me.$.outerHeight(true);
			var parentW = me.parent.$.width();
			var parentH = me.parent.$.height();
			var left = parseInt((parentW - width) / 2);
			var top = parseInt((parentH - height) / 2);
			me.$.css('left',left + 'px').css('top', top + 'px');
		};

		var state = {
		};
		// maximize toggle function
		var onMaximizeClick = function() {
			if(options && !options.maximizable)
				return;
			if(me.$.hasClass('maximized')) {
				me.$.removeClass('maximized');
				maximizeIcon.$.attr('src', '/Images/Icons/OOS/maximize.png');
				me.$.width(state.width).height(state.height).offset({left: state.left, top: state.top});
			} else {
				state.top = me.$.offset().top;
				state.left = me.$.offset().left;
				state.width = me.$.width();
				state.height = me.$.height();
				me.$.addClass('maximized');
				maximizeIcon.$.attr('src', '/Images/Icons/OOS/windowed.png');
				me.$.offset({left: 0, top: 0}).width(me.parent.$.width()).height(me.parent.$.height());
			}
			content.containerResized();
		};
		// drag functions
		var mouseStartDragX;
		var mouseStartDragY;
		var onTitleBarMouseDown = function(e) {
			if(me.$.hasClass('maximized'))
				return;
			state.top = me.$.offset().top;
			state.left = me.$.offset().left;
			mouseStartDragX = e.pageX;
			mouseStartDragY = e.pageY;
			$(window).mousemove(onMouseMove).mouseup(onMouseUp);
		};
		var onMouseMove = function(e) {
			var dx = e.pageX - mouseStartDragX;
			var dy = e.pageY - mouseStartDragY;
			me.$.offset({left: state.left + dx, top: state.top + dy});
		};
		var onMouseUp = function() {
			$(window).unbind('mousemove', onMouseMove).unbind('mouseup', onMouseUp);
		};
		// resize functions
		var resizeState = {
			isLeft:false,
			nearLeft:false,
			isRight:false,
			nearRight:false,
			isTop:false,
			nearTop:false,
			isBottom:false,
			nearBottom:false,
			isTopLeft:false,
			isTopRight:false,
			isBottomLeft:false,
			isBottomRight:false,
			isResizing:false,
			resizeBottomRightMove: function(e) {
				var dx = e.pageX - resizeState.startPos.x;
				var dy = e.pageY - resizeState.startPos.y;
				me.$.width(resizeState.startState.width + dx).height(resizeState.startState.height + dy);
				content.containerResized();
			},
			resizeBottomRightUp: function() {
				$(window).unbind('mousemove', resizeState.resizeBottomRightMove).unbind('mouseup', resizeState.resizeBottomRightUp);
				resizeState.isResizing = false;
			},
			resizeBottomLeftMove: function(e) {
				var dx = e.pageX - resizeState.startPos.x;
				var dy = e.pageY - resizeState.startPos.y;
				me.$.width(resizeState.startState.width - dx).height(resizeState.startState.height + dy);
				me.$.offset({left: resizeState.startState.left + dx, top: resizeState.startState.top});
				content.containerResized();
			},
			resizeBottomLeftUp: function() {
				$(window).unbind('mousemove', resizeState.resizeBottomLeftMove).unbind('mouseup', resizeState.resizeBottomLeftUp);
				resizeState.isResizing = false;
			},
			resizeRightMove: function(e) {
				var dx = e.pageX - resizeState.startPos.x;
				me.$.width(resizeState.startState.width + dx).height(resizeState.startState.height);
				content.containerResized();
			},
			resizeRightUp: function() {
				$(window).unbind('mousemove', resizeState.resizeRightMove).unbind('mouseup', resizeState.resizeRightUp);
				resizeState.isResizing = false;
			},
			resizeBottomMove: function(e) {
				var dy = e.pageY - resizeState.startPos.y;
				me.$.width(resizeState.startState.width).height(resizeState.startState.height + dy);
				content.containerResized();
			},
			resizeBottomUp: function() {
				$(window).unbind('mousemove', resizeState.resizeBottomMove).unbind('mouseup', resizeState.resizeBottomUp);
				resizeState.isResizing = false;
			},
			resizeTopLeftMove: function(e) {
				var dx = e.pageX - resizeState.startPos.x;
				var dy = e.pageY - resizeState.startPos.y;
				me.$.width(resizeState.startState.width - dx).height(resizeState.startState.height - dy);
				me.$.offset({left: resizeState.startState.left + dx, top: resizeState.startState.top + dy});
				content.containerResized();
			},
			resizeTopLeftUp: function() {
				$(window).unbind('mousemove', resizeState.resizeTopLeftMove).unbind('mouseup', resizeState.resizeTopLeftUp);
				resizeState.isResizing = false;
			},
			resizeTopRightMove: function(e) {
				var dy = e.pageY - resizeState.startPos.y;
				var dx = e.pageX - resizeState.startPos.x;
				me.$.width(resizeState.startState.width + dx).height(resizeState.startState.height - dy);
				me.$.offset({left: resizeState.startState.left, top: resizeState.startState.top + dy});
				content.containerResized();
			},
			resizeTopRightUp: function() {
				$(window).unbind('mousemove', resizeState.resizeTopRightMove).unbind('mouseup', resizeState.resizeTopRightUp);
				resizeState.isResizing = false;
			},
			resizeTopMove: function(e) {
				var dy = e.pageY - resizeState.startPos.y;
				me.$.width(resizeState.startState.width).height(resizeState.startState.height - dy);
				me.$.offset({left: resizeState.startState.left, top: resizeState.startState.top + dy});
				content.containerResized();
			},
			resizeTopUp: function() {
				$(window).unbind('mousemove', resizeState.resizeTopMove).unbind('mouseup', resizeState.resizeTopUp);
				resizeState.isResizing = false;
			},
			resizeLeftMove: function(e) {
				var dx = e.pageX - resizeState.startPos.x;
				me.$.width(resizeState.startState.width - dx).height(resizeState.startState.height);
				me.$.offset({left: resizeState.startState.left + dx, top: resizeState.startState.top});
				content.containerResized();
			},
			resizeLeftUp: function() {
				$(window).unbind('mousemove', resizeState.resizeLeftMove).unbind('mouseup', resizeState.resizeLeftUp);
				resizeState.isResizing = false;
			}
		};

		me.$.mousedown(function(e) {
			if(desktop.setFocus)
				desktop.setFocus(me);
			// if maximized, do not allow resize
			if(me.$.hasClass('maximized'))
				return;
			// assign status and events
			resizeState.startPos = { x: e.pageX, y: e.pageY };
			resizeState.startState = { left: me.$.offset().left, top: me.$.offset().top, width: me.$.width(), height: me.$.height() };
			if(resizeState.isBottomRight) {
				$(window).mousemove(resizeState.resizeBottomRightMove).mouseup(resizeState.resizeBottomRightUp);
				resizeState.isResizing = true;
			} else if(resizeState.isTopLeft) {
				$(window).mousemove(resizeState.resizeTopLeftMove).mouseup(resizeState.resizeTopLeftUp);
				resizeState.isResizing = true;
			} else if(resizeState.isBottomLeft) {
				$(window).mousemove(resizeState.resizeBottomLeftMove).mouseup(resizeState.resizeBottomLeftUp);
				resizeState.isResizing = true;
			} else if(resizeState.isTopRight) {
				$(window).mousemove(resizeState.resizeTopRightMove).mouseup(resizeState.resizeTopRightUp);
				resizeState.isResizing = true;
			}  else if(resizeState.isBottom) {
				$(window).mousemove(resizeState.resizeBottomMove).mouseup(resizeState.resizeBottomUp);
				resizeState.isResizing = true;
			}  else if(resizeState.isRight) {
				$(window).mousemove(resizeState.resizeRightMove).mouseup(resizeState.resizeRightUp);
				resizeState.isResizing = true;
			} else if(resizeState.isTop) {
				$(window).mousemove(resizeState.resizeTopMove).mouseup(resizeState.resizeTopUp);
				resizeState.isResizing = true;
			} else if(resizeState.isLeft) {
				$(window).mousemove(resizeState.resizeLeftMove).mouseup(resizeState.resizeLeftUp);
				resizeState.isResizing = true;
			}
		});
		me.$.mousemove(function(e) {
			if(resizeState.isResizing || me.$.hasClass('maximized') || (options && !options.resizable))
				return;
			// assign cursor (for resize events)
			me.$.css('cursor', '');
			var dx = e.pageX - me.$.offset().left;
			var dy = e.pageY - me.$.offset().top;
			var width = me.$.outerWidth(true);
			var height = me.$.outerHeight(true);
			// hit boxes for cursor
			var left = parseInt(me.$.css('border-left-width')) + parseInt(me.$.css('padding-left'));
			var top = parseInt(me.$.css('border-top-width')) + parseInt(me.$.css('padding-top'));
			var right = parseInt(me.$.css('border-right-width')) + parseInt(me.$.css('padding-right'));
			var bottom = parseInt(me.$.css('border-bottom-width')) + parseInt(me.$.css('padding-bottom'));

			resizeState.isLeft = (dx < left) && (dx > -left);
			resizeState.nearLeft = (dx - 12 < left) && (dx > -left);
			resizeState.isRight = (width - dx < right) && (width - dx > -right);
			resizeState.nearRight = (width - dx - 12 < right) && (width - dx > -right);
			resizeState.isTop = (dy < top) && (dy > -top);
			resizeState.nearTop = (dy - 12 < top) && (dy > -top);
			resizeState.isBottom = (height - dy < bottom) && (height - dy > -bottom);
			resizeState.nearBottom = (height - dy - 12 < bottom) && (height - dy > -bottom);
			resizeState.isTopLeft = (resizeState.isTop && resizeState.nearLeft) || (resizeState.nearTop && resizeState.isLeft);
			resizeState.isTopRight = (resizeState.isTop && resizeState.nearRight) || (resizeState.nearTop && resizeState.isRight);
			resizeState.isBottomLeft = (resizeState.isBottom && resizeState.nearLeft) || (resizeState.nearBottom && resizeState.isLeft);
			resizeState.isBottomRight = (resizeState.isBottom && resizeState.nearRight) || (resizeState.nearBottom && resizeState.isRight);
			if(resizeState.isLeft) {
				if(resizeState.nearTop) {
					me.$.css('cursor', 'se-resize');
				} else if(resizeState.nearBottom) {
					me.$.css('cursor', 'ne-resize');
				} else {
					me.$.css('cursor', 'e-resize');
				}
			} else if(resizeState.isRight) {
				if(resizeState.nearTop) {
					me.$.css('cursor', 'ne-resize');
				} else if(resizeState.nearBottom) {
					me.$.css('cursor', 'se-resize');
				} else {
					me.$.css('cursor', 'e-resize');
				}
			} else if(resizeState.isTop) {
				if(resizeState.nearLeft) {
					me.$.css('cursor', 'se-resize');
				} else if(resizeState.nearRight) {
					me.$.css('cursor', 'sw-resize');
				} else {
					me.$.css('cursor', 's-resize');
				}
			} else if(resizeState.isBottom) {
				if(resizeState.nearLeft) {
					me.$.css('cursor', 'sw-resize');
				} else if(resizeState.nearRight) {
					me.$.css('cursor', 'se-resize');
				} else {
					me.$.css('cursor', 's-resize');
				}
			}
		});

		me.setTitle = function(title) {
			if(title) {
				text.$.text(title);
				taskbarButton.$.attr('title', title);
			}
		};

		if(title)
			me.setTitle(title);

		if(desktop.parent && desktop.parent.taskBar) {
			if(taskbarIcon)
				taskbarIcon.$.appendTo(taskbarButton.$);
			taskbarButton.$.appendTo(desktop.parent.taskBar.programBar.$);
		}
		titleBar.$.appendTo(me.$);
		content.$.appendTo(me.$);
		if(icon)
			icon.$.appendTo(titleBar.$);
		text.$.appendTo(titleBar.$);
		actions.$.appendTo(titleBar.$);
		minimize.$.appendTo(actions.$);
		maximize.$.appendTo(actions.$);
		close.$.appendTo(actions.$);
		
		me.parent = desktop;

		maximize.$.click(onMaximizeClick);
		titleBar.$.dblclick(onMaximizeClick);
		titleBar.$.mousedown(onTitleBarMouseDown);
		minimize.$.click(function() {
			desktop.setFocus(null);
			me.$.hide();
		});
		me.close = function() {
			if(desktop.removeWindow)
				desktop.removeWindow(me);
			me.$.remove();
			taskbarButton.$.remove();
		};
		close.$.click(me.close);

		me.containerResized = function() {
			if(me.$.hasClass('maximized')) {
				me.$.width(desktop.$.width()).height(desktop.$.height());
				content.containerResized();
			}
		};

		me.focus = function() {
			me.$.addClass('focus');
			taskbarButton.$.addClass('down');
		};
		me.unfocus = function() {
			me.$.removeClass('focus');
			taskbarButton.$.removeClass('down');
		};

		taskbarButton.$.click(function() {
			if(taskbarButton.$.hasClass('down')) {
				desktop.setFocus(null);
				me.$.hide();
			} else {
				if(!me.$.is(':visible'))
					me.$.show();
				desktop.setFocus(me);
			}
		});

		if(options) {
			if(!options.minimizable)
				minimize.$.hide();
			if(!options.maximizable)
				maximize.$.hide();
		}

		return me;
	};
	ctor.Dialog = function(parent, iconSrc, title, width, height, options) {
		options = options || { };
		var me = new ctor.Window(parent, iconSrc, title, width, height, options);
		me.$.addClass('focus').addClass('dialog');
		return me;
	};
	ctor.ModalDialog = function(parent, iconSrc, title, width, height, options) {
		var me = new ctor.Dialog(parent, iconSrc, title, width, height, options);
		me.$.addClass('modal');
		return me;
	};
	ctor.MessageDialog = function(parent, iconSrc, title, width, height, options) {
		var me = new ctor.ModalDialog(parent, iconSrc, title, width, height, options);
		me.$.addClass('message');
		var text = new ctor.Object({tagName:'div', className: 'text'});
		var actions = new ctor.Object({tagName:'div', className: 'actions'});
		text.$.appendTo(me.content.$);
		actions.$.appendTo(me.content.$);
		me.text = text;
		me.actions = actions;
		if(options.buttons) {
			var i = 0;
			for(;i<options.buttons.length;i++) {
				var button = new ctor.Button({parent: me, tagName:'div', caption: options.buttons[i].text, className: options.buttons[i].className});
				if(options.buttons[i].action)
					button.$.click(options.buttons[i].action);
				button.$.appendTo(actions.$);
			}
		}
		return me;
	};
	ctor.FileDialog = function(parent, iconSrc, title, width, height, options) {
		options.resizable = true;
		var currentPath = 'C:\\';
		var currentExtension = '*.txt';
		var me = new ctor.ModalDialog(parent, iconSrc, title, width, height, options);
		var listView = new ctor.TableView(me, 'small');
		var filters = new ctor.Object({tagName:'div', className: 'filters'});
		var actions = new ctor.Object({tagName:'div', className: 'actions'});
		var extension = new ctor.Object({tagName:'select', className: 'extension'});
		extension.$.append($('<option value="*.txt">Fichiers texte (*.txt)</option><option value="*.*">Tous les fichiers (*.*)</option>'));
		var filenameLabel = new ctor.Object({tagName:'span', className: 'text'});
		filenameLabel.$.text('Nom du fichier : ');
		var filename = new ctor.Object({html: '<div class="filename"><input class="filename" type="text" /></div>'});
		var $filename = $('input.filename', filename.$);
		me.$.addClass('file');
		listView.$.appendTo(me.content.$);
		filenameLabel.$.appendTo(filters.$);
		filename.$.appendTo(filters.$);
		extension.$.appendTo(filters.$);
		filters.$.appendTo(me.content.$);
		actions.$.appendTo(me.content.$);
		me.actions = actions;
		var buttons = [];
		if(options.buttons) {
			var i = 0;
			for(;i<options.buttons.length;i++) {
				
				var button = new ctor.Button({tagName: 'div', parent: me, caption: options.buttons[i].text, className: options.buttons[i].className});
				buttons.push(button);
				if(options.buttons[i].action)
					button.$.click(options.buttons[i].action);
				button.$.appendTo(actions.$);
			}
		}
		extension.$.click(function() {
			if(extension.$.val() !== currentExtension) {
				currentExtension = extension.$.val();
				listView.refreshList(currentPath, currentExtension);
			}
		});
		var dblClickItem = function() {
			var $this = $(this);
			if($this.data('directory')) {
				currentPath = $this.data('path');
				listView.refreshList(currentPath, currentExtension);
			} else {
				me.selected = $this.data('path');
				$filename.val($this.data('name'));
				buttons[0].$.click();
			}
		};
		var clickItem = function() {
			var $this = $(this);
			if(!$this.data('directory')) {
				me.selected = $this.data('path');
				$filename.val($this.data('name'));
			}
		};
		var textChanged = function() {
			me.selected = (currentPath + '\\' + $filename.val()).replace('\\\\','\\');
		};
		$filename.keyup(textChanged);
		listView.$.on('dblclick', 'li.icon', dblClickItem);
		listView.$.on('dblclick', 'tr.icon', dblClickItem);
		listView.$.on('click', 'li.icon', clickItem);
		listView.$.on('click', 'tr.icon', clickItem);
		listView.refreshList(currentPath, currentExtension);
		var baseContainerResized = me.content.containerResized;
		me.content.containerResized = function() {
			if(baseContainerResized);
				baseContainerResized();
			var height = me.content.$.height();
			height -= filters.$.outerHeight(true);
			height -= actions.$.outerHeight(true);
			listView.$.height(height);
			listView.containerResized();
			filters.containerResized();
		};
		return me;
	};

	ctor.ContextMenu = function(parent) {
		var me = new ctor.Object({tagName: 'div', className: 'menu'});
		me.$.addClass('context');
		var list = new ctor.Object({tagName: 'ol', className: 'menuStrip'});
		list.$.appendTo(me.$);
		me.$.click(function() { me.$.hide(); })
		me.list = list;
		list.addItem = addItem;
		return me;
	};

	ctor.NavigationBar = function(window) {
		var me = new ctor.Object({tagName: 'div', className: 'navigationBar'});
		var previousButton = me.previousButton = new ctor.Object({tagName: 'img', emptyTag:true, className: 'previous', src: '/Images/Icons/OOS/previous.off.png', alt: 'Previous'});
		var nextButton = me.nextButton = new ctor.Object({tagName: 'img', emptyTag:true, className: 'next', src: '/Images/Icons/OOS/next.off.png', alt: 'Next'});
		var location = new ctor.Object({tagName: 'div', className: 'location'});
		var locationText = me.locationText = new ctor.Object({tagName: 'input', emptyTag: true, className: 'location'});
		var locationBrowser = me.locationBrowser = new ctor.Object({tagName:'ol', className: 'location'});
		var refreshButton = me.refreshButton = new ctor.Object({tagName: 'img', emptyTag:true, className: 'refresh', src: '/Images/Icons/OOS/refresh.png', alt: 'Refresh'});
		var search = new ctor.Object({tagName: 'div', className: 'search'});
		var searchText = new ctor.Object({tagName: 'input', emptyTag: true, className: 'search'});
		var searchButton = me.searchButton = new ctor.Object({tagName: 'img', emptyTag:true, className: 'search', src: '/Images/Icons/OOS/search.png', alt: 'Search'});

		me.$.append(previousButton.$);
		me.$.append(nextButton.$);
		me.$.append(location.$);
		me.$.append(search.$);

		location.$.append(locationBrowser.$);
		location.$.append(locationText.$);
		location.$.append(refreshButton.$);
		search.$.append(searchText.$);
		search.$.append(searchButton.$);

		setMouseEnterLeaveImages(previousButton.$, '/Images/Icons/OOS/previous.hover.png', '/Images/Icons/OOS/previous.png');
		setMouseEnterLeaveImages(nextButton.$, '/Images/Icons/OOS/next.hover.png', '/Images/Icons/OOS/next.png');
		setMouseEnterLeaveImages(searchButton.$, '/Images/Icons/OOS/search.hover.png', '/Images/Icons/OOS/search.png');
		setMouseEnterLeaveImages(refreshButton.$, '/Images/Icons/OOS/refresh.hover.png', '/Images/Icons/OOS/refresh.png');

		var currentIndex = -1;
		var paths = [];

		var buildPathMap = function(path) {
			searchText.$.attr('placeholder', 'Rechercher dans : ' + path)
			var pathMap = path.split('\\');
			var i =0;
			locationBrowser.$.html('');
			for(;i<pathMap.length;i++) {
				var li = new ctor.Object({tagName:'li', className: 'icon'});
				var span = new ctor.Object({tagName:'span', className: 'text'});
				span.$.text(pathMap[i]);
				li.$.append(span.$);
				if(i + 1 < pathMap.length) {
					var expand = new ctor.Object({tagName: 'img', emptyTag: true, src: '/Images/Icons/OOS/expand.png', className: 'expand'})
					li.$.append(expand.$);
				}
				locationBrowser.$.append(li.$);
			}
			return pathMap;
		};

		me.add = function(path) {
			currentIndex += 1;
			while(currentIndex < paths.length) {
				paths.pop();
			}
			paths.push(path);
			if(currentIndex - 1 >= 0)
				previousButton.$.attr('src', '/Images/Icons/OOS/previous.png');
			nextButton.$.attr('src', '/Images/Icons/OOS/next.off.png');
			locationText.$.val(path);
			buildPathMap(path);
		};
		me.next = function() {
			if(currentIndex + 1 < paths.length) {
				currentIndex += 1;
				if(currentIndex + 1 >= paths.length)
					nextButton.$.attr('src', '/Images/Icons/OOS/next.off.png');
				previousButton.$.attr('src', '/Images/Icons/OOS/previous.png');
				locationText.$.val(paths[currentIndex]);
				buildPathMap(paths[currentIndex]);
				return paths[currentIndex];
			}
			return null;
		};
		me.previous = function() {
			if(currentIndex - 1 >= 0) {
				currentIndex -= 1;
				if(currentIndex -1 < 0)
					previousButton.$.attr('src', '/Images/Icons/OOS/previous.off.png');
				nextButton.$.attr('src', '/Images/Icons/OOS/next.png');
				locationText.$.val(paths[currentIndex]);
				buildPathMap(paths[currentIndex]);
				return paths[currentIndex];
			}
			return null;
		};

		return me;
	};

	ctor.ExplorerWindow = function(desktop, iconSrc, title, width, height) {
		var me = desktop.addWindow(iconSrc, title, width, height);
		me.$.addClass('explorer');
		var navigationBar = new ctor.NavigationBar(me);
		var hierarchyView = new ctor.HierarchyView(me, 'small');
		var listView = new ctor.TableView(me, 'small');
		me.content.$.append(navigationBar.$);
		hierarchyView.$.appendTo(me.content.$);
		listView.$.appendTo(me.content.$);
		var baseContainerResized = me.content.containerResized;
		me.content.containerResized = function() {
			if(baseContainerResized);
				baseContainerResized();
			navigationBar.$.hide();
			listView.$.hide();
			hierarchyView.$.hide();
			var height = me.content.$.height();
			var width = me.content.$.width();
			listView.$.show();
			hierarchyView.$.show();
			navigationBar.$.show();
			listView.$.height(height - listView.$.position().top ).width(width - hierarchyView.$.width() - 5);
			hierarchyView.$.height(height - hierarchyView.$.position().top);
			listView.containerResized();
		};

		var previousClick = function() {
			var path = navigationBar.previous();
			if(path) {
				me.setTitle(path);
				listView.refreshList(path, '*');
			}
		};
		var nextClick = function() {
			var path = navigationBar.next();
			if(path) {
				me.setTitle(path);
				listView.refreshList(path, '*');
			}
		};
		var setLocation = function(path) {
			if(path) {
				me.setTitle(path);
				navigationBar.add(path);
				listView.refreshList(path, '*');
			}
		};

		var currentLocation = null;

		var showLocationText = function(e) {
			if(e.target === this) {
				navigationBar.locationBrowser.$.hide();
				navigationBar.locationText.$.show().focus();
				currentLocation = navigationBar.locationText.$.val();
			}
		};
		var hideLocationText = function(e) {
			var $this = $(this);
			if(e.keyCode === 13) {
				if($this.val() !== currentLocation)
					setLocation($this.val());
				navigationBar.locationBrowser.$.show();
				navigationBar.locationText.$.hide();
			}
		};

		navigationBar.locationBrowser.$.click(showLocationText);
		navigationBar.locationText.$.keydown(hideLocationText);
		navigationBar.locationText.$.blur(function() {
			var $this = $(this);
			if($this.val() !== currentLocation)
				setLocation($this.val());
			navigationBar.locationBrowser.$.show();
			navigationBar.locationText.$.hide();
		});
		navigationBar.previousButton.$.click(previousClick);
		navigationBar.nextButton.$.click(nextClick);

		var clickItem = function(e) {
			e.stopPropagation();
			var $this = $(this.parentNode);
			if($this.data('directory')) {
				var path = $this.data('path');
				me.setTitle(path);
				navigationBar.add(path);
				listView.refreshList(path, '*');
			}
		};

		var dblClickItem = function(e) {
			e.stopPropagation();
			var $this = $(this);
			if($this.data('directory')) {
				var path = $this.data('path');
				me.setTitle(path);
				navigationBar.add(path);
				listView.refreshList(path, '*');
			}
		};

		hierarchyView.$.on('click', 'li.icon>div.content', clickItem);
		listView.$.on('dblclick', 'li.icon', dblClickItem);
		listView.$.on('dblclick', 'tr.icon', dblClickItem);

		me.content.containerResized();

		hierarchyView.refreshList('C:\\');
		me.setPath = function(path) {
			listView.refreshList(path, '*');
			navigationBar.add(path);
		};
		return me;
	};
	ctor.NotepadWindow = function(desktop, iconSrc, title, width, height) {
		var me = desktop.addWindow(iconSrc, title, width, height);
		me.$.addClass('notepad');
		var textbox = new ctor.Object({tagName:'textarea', className: 'notepad'});
		me.content.children.push(textbox);
		textbox.parent = me.content;
		textbox.containerResized = fillParent;
		textbox.$.appendTo(me.content.$);

		var openedFilePath = null;
		var newFile = function() {
			textbox.$.val('');
			openedFilePath = null;
			me.caption.$.text('Sans titre - Bloc-notes');
		};
		var saveFileAs = function() {
			var dialog = new ctor.FileDialog(me, null, 'Enregistrer sous', 800, 500, {buttons:[
				{text:'Enregistrer', action: function() { openedFilePath = dialog.selected; saveFile(); dialog.$.remove(); }},
				{text:'Annuler', action: function() { dialog.$.remove(); }}
			]});
			dialog.$.appendTo(me.$);
			dialog.trimHeight();
			dialog.$.height(dialog.$.height() + dialog.actions.$.outerHeight(true));
			dialog.centerParent();
			dialog.content.containerResized();
			me.setFocus(dialog);
		};
		var saveFile = function() {
			if(!openedFilePath)
				saveFileAs();
			else {
				oos.saveText(openedFilePath, textbox.$.val(), function(data) {
					me.caption.$.text(openedFilePath + ' - Bloc-notes');
				}, function() { alert('error'); });
			}
		};
		var checkSaveChanges = function(func) {
			if(textbox.$.val() !== '') {
				var dialog = new ctor.MessageDialog(me, null, 'Bloc-notes', 400, 120, {buttons:[
					{text: 'Enregistrer', action: function() { saveFile(); dialog.$.remove(); if(func) { textbox.$.val(''); func(); } }},
					{text: 'Ne pas enregistrer', action: function() { newFile(); dialog.$.remove(); if(func) { textbox.$.val(''); func(); } }},
					{text: 'Annuler', action: function() { dialog.$.remove(); }}
				]});
				dialog.text.$.text('Voulez-vous enregistrer les modifications de ' + (openedFilePath ? openedFilePath : 'Sans titre') + ' ?');
				dialog.$.appendTo(me.$);
				dialog.trimHeight();
				dialog.centerParent();
				dialog.content.containerResized();
				me.setFocus(dialog);
			}
		};
		var openFile = function() {
			if(textbox.$.val() !== '') {
				checkSaveChanges(openFile);
				return;
			}
			var dialog = new ctor.FileDialog(me, null, 'Ouvrir', 800, 500, {buttons:[
				{text:'Ouvrir', action: function() {
					if(dialog.selected) {
						oos.retrieveText(dialog.selected, function(data) {
							// dont think it's really safe
							openedFilePath = dialog.selected;
							me.caption.$.text((openedFilePath ? openedFilePath : 'Sans titre') + ' - Bloc-notes');
							if(data.content)
								textbox.$.val(data.content);
							else
								textbox.$.val('');
						}, function() { alert('error'); });
						dialog.$.remove();
					}
				}},
				{text:'Annuler', action: function() { dialog.$.remove(); }}
			]});
			dialog.$.appendTo(me.$);
			dialog.centerParent();
			dialog.content.containerResized();
			me.setFocus(dialog);
		};
		
		var fileItem = me.addMenuItem('Fichier');
		fileItem.addItem('Nouveau').$.click(function() { checkSaveChanges(); });
		fileItem.addItem('Ouvrir...').$.click(openFile);
		fileItem.addItem('Enregistrer').$.click(saveFile);
		fileItem.addItem('Enregistrer sous...', 'separationBottom').$.click(saveFileAs);
		fileItem.addItem('Mise en page...', 'separationTop');
		fileItem.addItem('Imprimer...', 'separationBottom');
		fileItem.addItem('Quitter', 'separationTop').$.click(me.close);
		var editItem = me.addMenuItem('Edition');
		editItem.addItem('Annuler', 'separationBottom', true);
		editItem.addItem('Couper', 'separationTop', true);
		editItem.addItem('Copier', null, true);
		editItem.addItem('Coller', null, true);
		editItem.addItem('Supprimer', 'separationBottom', true);
		editItem.addItem('Rechercher...', 'separationTop', true);
		editItem.addItem('Rechercher le suivant', true);
		editItem.addItem('Remplacer...');
		editItem.addItem('Atteindre...', 'separationBottom');
		editItem.addItem('Sélectionner tout', 'separationTop');
		editItem.addItem('Heure/Date');
		var formatItem = me.addMenuItem('Format');
		formatItem.addItem('Retour à la ligne automatique');
		formatItem.addItem('Police...');
		var displayItem = me.addMenuItem('Affichage');
		displayItem.addItem('Barre d\'état');
		var helpItem = me.addMenuItem('?');
		helpItem.addItem('Afficher l\'aide', 'separationBottom');
		helpItem.addItem('A propos du Bloc-notes', 'separationTop');
		return me;
	};

	$(function() {
		j.console.info('>: Loading OnlineOS ...');
		// deactivate context menu right click
		$(window).bind('contextmenu', windowContextMenu);
		// create screen object
		oos.screen = new ctor.Screen();
		// initialize screen size
		oos.sfn.windowResize();
		// assign resize window event
		$(window).resize(oos.sfn.windowResize);

		var openNotepad = function() {
			var notepad = new ctor.NotepadWindow(oos.screen.desktop, '/Images/Icons/OOS/Notepad.png', 'Sans titre - Bloc-notes', 800, 600);
		};
		var openExplorer = function() {
			var $this = $(this);
			var explorer = new ctor.ExplorerWindow(oos.screen.desktop, '/Images/Icons/OOS/Folder.png', $this.data('path'), 800, 600);
			var path = $this.data('path');
			var directory = $this.data('directory');
			if(directory && path) {
				explorer.setPath(path);
			}
		};

		var icon = oos.screen.desktop.addIcon('/Images/Icons/OOS/Notepad.png',{name:'Bloc-notes'});
		icon.$.dblclick(openNotepad);

		oos.screen.startMenu.addRightItem('Root');
		oos.screen.startMenu.addRightItem('Documents');
		oos.screen.startMenu.addRightItem('Images');
		oos.screen.startMenu.addRightItem('Musique', 'separationBottom');
		oos.screen.startMenu.addRightItem('Jeux', 'separationTop');
		oos.screen.startMenu.addRightItem('Ordinateur', 'separationBottom');
		oos.screen.startMenu.addRightItem('Panneau de configuration', 'separationTop');
		oos.screen.startMenu.addRightItem('Périphériques et imprimantes');
		oos.screen.startMenu.addRightItem('Programmes par défaut');
		oos.screen.startMenu.addRightItem('Aide et support');

		oos.screen.startMenu.addLeftItem('Microsoft Visual Studio 2010', null, '/Images/html5-icon.png');
		oos.screen.startMenu.addLeftItem('Connexion Bureau à distance', 'separationBottom', '/Images/html5-icon.png');
		oos.screen.startMenu.addLeftItem('SimCity', 'separationTop', '/Images/html5-icon.png');
		oos.screen.startMenu.addLeftItem('Origin', null, '/Images/html5-icon.png');
		oos.screen.startMenu.addLeftItem('Paint', null, '/Images/html5-icon.png');
		oos.screen.startMenu.addLeftItem('Internet Explorer', null, '/Images/html5-icon.png');
		oos.screen.startMenu.addLeftItem('PokerStars.BE', null, '/Images/html5-icon.png');
		oos.screen.startMenu.addLeftItem('Calculatrice', null, '/Images/html5-icon.png');
		oos.screen.startMenu.addLeftItem('Adobe Photoshop CS4 (64 Bit)', null, '/Images/html5-icon.png');
		oos.screen.startMenu.addLeftItem('Minecraft', null, '/Images/html5-icon.png');
		oos.screen.startMenu.addLeftItem('StarCraft II', null, '/Images/html5-icon.png');
		oos.screen.startMenu.addLeftItem('Bloc-notes', 'separationBottom', '/Images/Icons/OOS/Notepad.png').$.click(openNotepad);
		oos.screen.startMenu.addLeftItem('Tous les programmes', 'separationTop', '/Images/html5-icon.png');

		
		var retrieveDirectory = function(path, filter, onlyDirectory, success, error) {
			j.sfn.submitAjaxData({
				format: 'json',
				directory: path,
				onlyDirectory: onlyDirectory,
				filter: filter
			}, 'oos.html', 'post', success, error);
		};
		var retrieveText = function(path, success, error) {
			j.sfn.submitAjaxData({
				format: 'json',
				content: path
			}, 'oos.html', 'post', success, error);
		};
		var saveText = function(path, text, success, error) {
			j.sfn.submitAjaxData({
				format: 'json',
				save: path,
				data: text
			}, 'oos.html', 'post', success, error);
		};
		oos.retrieveDirectory = retrieveDirectory;
		oos.retrieveText = retrieveText;
		oos.saveText = saveText;

		retrieveDirectory('C:\\', null, false, function(data) {
			var size = parseInt(oos.screen.desktop.$.width() / 96);
			if(data.directory) {
				var i = 0;
				for(;i<data.directory.length;i++) {
					var srcIcon = getItemIcon(data.directory[i]);
					var icon = oos.screen.desktop.addIcon(srcIcon,data.directory[i]);
					var ix = (i + 1) % size;
					var iy = parseInt((i + 1) / size);

					icon.$.offset({left: ix * icon.$.width(), top: iy * icon.$.height()});
					if(data.directory[i].type === 'directory')
						icon.$.dblclick(openExplorer);
				}
			}
		}, function() {
			alert('error');
		});

		j.console.info('>: OnlineOS loaded successfully.');
	});


	return oos;

}($, JAYDEN));